<?php

namespace App\Kuafu\Activity\Validate;

use App\Exceptions\CustomValidateException;
use App\Http\Validate\AbstractBaseValidate;
use App\Kuafu\Activity\Enum\ActivityCodeEnum;
use App\Kuafu\Activity\Enum\ActivityEnum;
use App\Kuafu\Activity\Exceptions\ActivityException;
use App\Kuafu\Activity\Model\ActivityModel;
use App\Kuafu\Coupon\Model\CouponModel;
use App\Kuafu\Product\Model\Product;
use App\Kuafu\Shop\Model\Shop;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class ActivityNewValidate extends AbstractBaseValidate
{
    /**
     * @inheritDoc
     */
    function getRules(): array
    {
        // TODO: Implement getRules() method.
        return [
            "id" => ["required", "int", Rule::exists("activities", "id")]
        ];
    }

    /**
     * @inheritDoc
     */
    function getAttributes(): array
    {
        // TODO: Implement getAttributes() method.
        return [];
    }

    /**
     * @inheritDoc
     */
    function registerValidateRules(): void
    {
        // TODO: Implement registerValidateRules() method.
    }

    /**
     * @inheritDoc
     */
    function getMessages(): array
    {
        // TODO: Implement getMessages() method.
        return [];
    }


    /**
     * @param array $params
     * @return MessageBag|object
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface|CustomValidateException
     */
    public static function detailValidate(array $params)
    {
        return self::getInstance()->validate(["id"], $params);
    }


    /**
     * 更新活动
     *
     * @param array $params
     * @return MessageBag|object
     * @throws ContainerExceptionInterface
     * @throws CustomValidateException
     * @throws NotFoundExceptionInterface
     */
    public static function updateValidate(array $params)
    {
        return self::getInstance()->validate(
            [
                "id",
                "limitJoinNum",
                "timeType",
                "startAt",
                "endAt",
                "description",
                "limitJoinNum",
                "imageList",
                'miniCardImage',
                'isAttendEd',
                'isAttendOpenActivity',
                'pushText',
            ],
            $params,
            [
                "id"                   => Rule::exists("activities", "id")
                                              ->where(function ($query) {
                                                  $query->where(function ($query) {
                                                      $query->where("status", ActivityEnum::STATUS_SUSPEND)
                                                            ->where("endAt", ">", time());
                                                  })->orWhere("startAt", ">", time());
                                              }),
                'timeType'             => self::intInValidateBuild(true, ActivityEnum::TIME_TYPES),
                'startAt'              => 'required_if:timeType,' . ActivityEnum::TIME_TYPE_SHORT . '|string|date_format:Y-m-d H:i:s',
                'endAt'                => 'required_if:timeType,' . ActivityEnum::TIME_TYPE_SHORT . '|string|date_format:Y-m-d H:i:s',
                "description"          => self::stringValidateBuild(false, 200),
                "limitJoinNum"         => "required|int|min:0",
                "imageList"            => "sometimes|array|min:2|max:2",
                'miniCardImage'        => '',
                'isAttendEd'           => '',
                'isAttendOpenActivity' => '',
                'pushText'             => '',
            ],
            true,
            function (array $params) {
                if (ActivityEnum::TIME_TYPE_LONG == $params['timeType']) {
                    // 长期活动
                    $params["startAt"] = 0;
                    $params["endAt"]   = ActivityEnum::MAX_END_AT;
                } else {
                    $params["startAt"] = strtotime($params["startAt"]);
                    $params["endAt"]   = strtotime($params["endAt"]);
                }

                $activity = ActivityModel::query()->where("id", $params["id"])->with("activityShopMappingRel")->first();
                if ($activity->type == ActivityEnum::TYPE_FULL_GIFT_ACTIVITY) {
                    ActivityModel::query()
                                 ->whereIn("status", [ActivityEnum::STATUS_RUNNING, ActivityEnum::STATUS_PREPARE])
                                 ->where("type", ActivityEnum::TYPE_FULL_GIFT_ACTIVITY)
                                 ->where("id", "<>", $params["id"])
                                 ->whereHas("activityShopMappingRel", function ($query) use ($params, $activity) {
                                     $query->where("shopId", $activity->activityShopMappingRel->toArray()[0]["shopId"]);
                                 })
                                 ->get()
                                 ->each(function (ActivityModel $activityModel) use (
                                     $params,
                                     &$coverActivity
                                 ) {
                                     $startCover = $activityModel->startAt >= $params["startAt"] && $activityModel->startAt <= $params["endAt"];
                                     $endCover   = $activityModel->endAt >= $params["startAt"] && $activityModel->endAt <= $params["endAt"];
                                     $allCover   = $activityModel->startAt < $params["startAt"] && $activityModel->endAt > $params["endAt"];
                                     if ($startCover || $endCover || $allCover) {
                                         throw new ActivityException(ActivityCodeEnum::ERR_ACTIVITY_TIME_COVER);
                                     }
                                 });
                }

                return $params;
            }
        );
    }

    /**
     * 创建活动预校验
     *
     * @param array $params
     * @return MessageBag|object
     * @throws ContainerExceptionInterface
     * @throws CustomValidateException
     * @throws NotFoundExceptionInterface
     */
    public static function createActivityPreValidate(array $params)
    {
        return self::getInstance()->validate(
            ['type'],
            $params,
            ['type' => self::intInValidateBuild(true, ActivityEnum::TYPES)]
        );
    }

    /**
     * 创建活动校验 - 日常活动
     *
     * @param int $type
     * @param array $params
     * @return MessageBag|object
     * @throws ContainerExceptionInterface
     * @throws CustomValidateException
     * @throws NotFoundExceptionInterface
     */
    public static function createActivityValidate_5(int $type, array $params)
    {
        return self::getInstance()->validate(
            [
                'name',
                'timeType',
                'startAt',
                'endAt',
                'coupons',
                'limitJoinNum',
                'shopType',
                'shopIds',
                'description',
                'imageList',
                'pushText',
                'miniCardImage',
                'isAttendOpenActivity',
                'isAttendEd'
            ],
            $params,
            [
                'name'                 => self::stringValidateBuild(true, 50, 1),
                'timeType'             => self::intInValidateBuild(true, ActivityEnum::TIME_TYPES),
                'startAt'              => "exclude_unless:timeType," . ActivityEnum::TIME_TYPE_SHORT . "|required|date_format:Y-m-d H:i:s",
                'endAt'                => "exclude_unless:timeType," . ActivityEnum::TIME_TYPE_SHORT . "|required|date_format:Y-m-d H:i:s",
                'coupons'              => 'required|array|min:1',
                'coupons.*.couponId'   => [
                    "required",
                    "int",
                    Rule::exists((new CouponModel())->getTable(), "id")
                ],
                'coupons.*.num'        => 'required|int|min:1',
                'limitJoinNum'         => 'required|int|min:0|max:10000000',
                'shopType'             => self::intInValidateBuild(true, ActivityEnum::SHOP_TYPES),
                'shopIds'              => "exclude_unless:shopType," . ActivityEnum::SHOP_TYPE_SELECTION . "|required|array|min:1",
                'shopIds.*'            => [
                    "int",
                    Rule::exists((new Shop())->getTable(), "id")
                ],
                'description'          => 'sometimes|string|max:200',
                'imageList'            => "required|array|min:2|max:2",
                'imageList.*'          => "url",
                'isAttendEd'           => self::intInValidateBuild(true, ActivityEnum::IS_ATTEND_TEXT),
                'pushText'             => "exclude_unless:isAttendEd," . ActivityEnum::IS_ATTEND_YES . "|required|string|min:1|max:1000",
                'miniCardImage'        => "exclude_unless:isAttendEd," . ActivityEnum::IS_ATTEND_YES . "|required|url",
                'isAttendOpenActivity' => self::intInValidateBuild(true, ActivityEnum::IS_ATTEND_TEXT),
            ],
            true,
            function (array $params) {
                if ($params["timeType"] == ActivityEnum::TIME_TYPE_LONG) {
                    $params["startAt"] = 0;
                    $params["endAt"]   = ActivityEnum::MAX_END_AT;
                    $params["status"]  = ActivityEnum::STATUS_RUNNING;
                } else {
                    $params["startAt"] = strtotime($params["startAt"]);
                    $params["endAt"]   = strtotime($params["endAt"]);
                    $params["status"]  = ActivityEnum::STATUS_PREPARE;
                }

                return $params;
            }
        );
    }

    /**
     * 创建活动校验 - 满赠活动
     *
     * @param int $type
     * @param array $params
     * @return MessageBag|object
     * @throws ContainerExceptionInterface
     * @throws CustomValidateException
     * @throws NotFoundExceptionInterface
     */
    public static function createActivityValidate_6(int $type, array $params)
    {
        return self::getInstance()->validate(
            [
                'name',
                'timeType',
                'startAt',
                'endAt',
                'productType',
                'shopIds',
                'thresholdAmount',
                'suitProducts',
                'giveProducts',
                'channel',
                'posAutoJoin',
                'limitJoinNum',
                'description'
            ],
            $params,
            [
                'name'                             => self::stringValidateBuild(true, 50, 1),
                'timeType'                         => self::intInValidateBuild(true, ActivityEnum::TIME_TYPES),
                'startAt'                          => "exclude_unless:timeType," . ActivityEnum::TIME_TYPE_SHORT . "|required|date_format:Y-m-d H:i:s",
                'endAt'                            => "exclude_unless:timeType," . ActivityEnum::TIME_TYPE_SHORT . "|required|date_format:Y-m-d H:i:s",
                'limitJoinNum'                     => 'required|int|min:0|max:10000000',
                'shopIds'                          => "required|array|min:1|max:1",
                'shopIds.*'                        => [
                    "int",
                    Rule::exists((new Shop())->getTable(), "id")->where(function ($query) {
                        $query->where("menuId", ">", 0);
                    })
                ],
                'productType'                      => self::intInValidateBuild(true, ActivityEnum::PRODUCT_TYPE_TEXT),
                "suitProducts"                     => "exclude_unless:productType," . ActivityEnum::PRODUCT_TYPE_PART . "required|array|min:1",
                "suitProducts.*.productId"         => [
                    "required",
                    "int",
                    Rule::exists((new Product())->getTable(), "id")
                        ->where("menuId", Shop::query()->where("id", $params["shopIds"][0])->first()->menuId)
                        ->where("isDeleted", 0)
                ],
                "giveProducts"                     => "required|array",
                "giveProducts.*.productId"         => [
                    "required",
                    "int",
                    Rule::exists((new Product())->getTable(), "id")
                        ->where("menuId", Shop::query()->where("id", $params["shopIds"][0])->first()->menuId)
                        ->where("isDeleted", 0)
                ],
                "giveProducts.*.giveNum"           => [
                    "required",
                    "int",
                    "min:1",
                    "max:100"
                ],
                "giveProducts.*.giveStockRuleType" => [
                    "required",
                    "int",
                    "in:0,1"
                ],
                "giveProducts.*.stockNum"          => "exclude_unless:giveProducts.*.giveStockRuleType,1|required|int|min:1",
                'description'                      => 'sometimes|string|max:200',
                'channel'                          => "required|array|min:1",
                'channel.*'                        => [
                    "required",
                    "int",
                    "in:" . self::enumTransToRules(ActivityEnum::CHANNEL_TEXT)
                ],
                'posAutoJoin'                      => Rule::when(
                    in_array(ActivityEnum::CHANNEL_POS, $params["channel"] ?? []),
                    self::intInValidateBuild(true, ActivityEnum::AUTO_JOIN_TEXT),
                    ""
                ),
                'thresholdAmount'                  => "required|int|min:1"
            ],
            true,
            function (array $params) {
                if ($params["timeType"] == ActivityEnum::TIME_TYPE_LONG) {
                    $params["startAt"] = 0;
                    $params["endAt"]   = ActivityEnum::MAX_END_AT;
                    $params["status"]  = ActivityEnum::STATUS_RUNNING;
                } else {
                    $params["startAt"] = strtotime($params["startAt"]);
                    $params["endAt"]   = strtotime($params["endAt"]);
                    $params["status"]  = ActivityEnum::STATUS_PREPARE;
                }

                $params["channel"]  = collect($params["channel"])->implode(",");
                $params["shopType"] = ActivityEnum::SHOP_TYPE_SELECTION;

                // todo 判断是否存在已上架且交叉时间的活动
                ActivityModel::query()
                             ->whereIn("status", [ActivityEnum::STATUS_RUNNING, ActivityEnum::STATUS_PREPARE])
                             ->where("type", ActivityEnum::TYPE_FULL_GIFT_ACTIVITY)
                             ->whereHas("activityShopMappingRel", function ($query) use ($params) {
                                 $query->where("shopId", $params["shopIds"][0]);
                             })
                             ->get()
                             ->each(function (ActivityModel $activityModel) use (
                                 $params,
                                 &$coverActivity
                             ) {
                                 $startCover = $activityModel->startAt >= $params["startAt"] && $activityModel->startAt <= $params["endAt"];
                                 $endCover   = $activityModel->endAt >= $params["startAt"] && $activityModel->endAt <= $params["endAt"];
                                 $allCover   = $activityModel->startAt < $params["startAt"] && $activityModel->endAt > $params["endAt"];
                                 if ($startCover || $endCover || $allCover) {
                                     throw new ActivityException(ActivityCodeEnum::ERR_ACTIVITY_TIME_COVER);
                                 }
                             });

                return $params;
            }
        );
    }
}
